-- | Compact Intervals

module Iv (T, mk, lo, hi, dest, width, singl, mid, rad, ball, mem,
  intersect, union, subdivBox) where

data T a = Iv a a deriving (Eq)

instance Show a => Show (Iv.T a) where
  show (Iv a b) = "[" ++ shows a ", " ++ shows b "]"

instance Functor Iv.T where
  fmap f (Iv a b) = Iv (f a) (f b)

-- | Make an interval

mk :: a -> a -> Iv.T a
mk = Iv

-- | Lower bound

lo :: Iv.T t -> t
lo (Iv a _) = a

-- | Upper bound

hi :: Iv.T t -> t
hi (Iv _ b) = b

-- | Destruct an interval

dest :: Iv.T t -> (t, t)
dest (Iv a b) = (a,b)

-- | Singleton interval

singl :: a -> Iv.T a
singl a = Iv a a

-- | Centered interval

ball :: Num a => a -> a -> Iv.T a
ball c r = Iv (c-r) (c+r)

-- | Membership

mem :: Ord a => a -> Iv.T a -> Bool
mem x (Iv a b) = a <= x && x <= b

-- | Diameter

width :: Num a => Iv.T a -> a
width (Iv a b) = b - a

-- | Radius

rad :: Fractional a => Iv.T a -> a
rad (Iv a b) = (b - a)/2

-- | Midpoint

mid :: Fractional a => Iv.T a -> a
mid (Iv a b) = (a+b)/2

-- | Subdivide a box along the given dimension

subdivBox :: Fractional a => Int -> [Iv.T a] -> ([Iv.T a],[Iv.T a])
subdivBox k x = (x1 ++ Iv xk1 m : x2,
                 x1 ++ Iv m xk2 : x2)
  where (x1, Iv xk1 xk2:x2) = splitAt k x
        m = (xk1 + xk2) / 2

-- | Intersection

intersect :: Ord t => Iv.T t -> Iv.T t -> Iv.T t
intersect (Iv a1 a2) (Iv b1 b2) = Iv (max a1 b1) (min a2 b2)

-- | Union

union :: Ord t => Iv.T t -> Iv.T t -> Iv.T t
union     (Iv a1 a2) (Iv b1 b2) = Iv (min a1 b1) (max a2 b2)
